package com.zmcc.sender;

import com.google.gson.JsonParser;
import com.zmcc.entity.common.CommonRequest;
import com.zmcc.entity.common.CommonResponse;
import com.zmcc.exception.ApiException;
import com.zmcc.utils.GsonUtil;
import okhttp3.*;

import javax.net.ssl.*;
import java.io.File;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Map;

public class DefaultSyncClient implements ISyncClient {
    private OkHttpClient okHttpClient;
    private static DefaultSyncClient defaultSyncClient;

    private X509TrustManager getX509TrustManage() throws NoSuchAlgorithmException, KeyStoreException {
        TrustManagerFactory trustManagerFactory = TrustManagerFactory
                .getInstance(TrustManagerFactory.getDefaultAlgorithm());
        trustManagerFactory.init((KeyStore) null);
        TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
        if (trustManagers.length != 1
                || !(trustManagers[0] instanceof X509TrustManager)) {
            throw new IllegalStateException("Unexpected default trust managers:"
                    + Arrays.toString(trustManagers));
        }
        X509TrustManager trustManager = (X509TrustManager) trustManagers[0];
        return trustManager;
    }

    private SSLSocketFactory getSSLSocketFactory () throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, new TrustManager[] { getX509TrustManage() }, null);
        SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
        return sslSocketFactory;
    }

    public DefaultSyncClient() {
        try {
            this.okHttpClient = new OkHttpClient.Builder()
                    .sslSocketFactory(this.getSSLSocketFactory(), this.getX509TrustManage())
                    .followRedirects(false)
                    .build();
        } catch (KeyStoreException | NoSuchAlgorithmException | KeyManagementException e ) {
            throw new ApiException("instance default http client error");
        }
    }

    public static synchronized DefaultSyncClient getInstance() {
        if (defaultSyncClient == null) {
            defaultSyncClient = new DefaultSyncClient();
        }
        return defaultSyncClient;
    }

    private CommonResponse toCommonResponse(Response response) throws IOException {
        CommonResponse commonResponse = new CommonResponse();
        String body = response.body().string();
        commonResponse.setData(body);
        Map map =  GsonUtil.gsonToMaps(body);
        commonResponse.setCode(response.code());
        // TODO://check response code if error throw exception
        Integer resultCode = new JsonParser().parse(body).getAsJsonObject().get("resultCode").getAsInt();
        String resultMsg = new JsonParser().parse(commonResponse.getData()).getAsJsonObject().get("resultMsg").getAsString();
        if (resultCode != 200&&map.size()==2) { //todo 简单判断
            throw new ApiException(resultMsg);
        }
        return commonResponse;
    }

    @Override
    public CommonResponse uploadFile(CommonRequest commonRequest, File file) {
        RequestBody requestBody = new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("file",
                        file.getName(),
                        RequestBody.create(MediaType.parse("multipart/form-data"), file)
                        )
                .build();

        Headers.Builder headersBuilder = new Headers.Builder();
        for (Map.Entry<String, String> header:commonRequest.getHeaderParams().entrySet()) {
            headersBuilder.add(header.getKey(), header.getValue());
        }
        Request request = new Request.Builder()
                .url(commonRequest.getUrl())
                .headers(headersBuilder.build())
                .post(requestBody)
                .build();
        try(Response response = this.okHttpClient.newCall(request).execute()) {
            return toCommonResponse(response);
        } catch (IOException e) {
            throw new ApiException("fetch error");
        }

    }

    @Override
    public CommonResponse fetch(CommonRequest commonRequest) {
        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json;charset=UTF-8"),
                commonRequest.getBody());

        Headers.Builder headersBuilder = new Headers.Builder();
        for (Map.Entry<String, String> header:commonRequest.getHeaderParams().entrySet()) {
            headersBuilder.add(header.getKey(), header.getValue());
        }
        Request request = new Request.Builder()
                .url(commonRequest.getUrl())
                .headers(headersBuilder.build())
                .post(requestBody)
                .build();
        try(Response response = this.okHttpClient.newCall(request).execute()) {
            return toCommonResponse(response);
        } catch (IOException e) {
            throw new ApiException("fetch error");
        }
    }
}
